﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace DarkLight.Model
{
    public class Convoy : Orthonormality, ILocation
    {
        #region Data
        //private Effect _effect;

        //private InputLayout _trajLayout;
        //private List<Vector3> _trajVertices;
        //private List<float> _trajAlphas;
        
        //private float _startGameTime;
        //private float _elapsed;
        //private bool _needRefreshStartGameTime;
        //private float _progress;
        private float _duration;
        #endregion

        #region Constructors
        public Convoy(Fleet fleet, ILocation origin, ILocation destination, DateTime start, DateTime end)
        {
            Fleet = fleet;
            Origin = origin;
            Destination = destination;
            StartTime = start;
            EndTime = end;

            //_effect = this.CreateEffect(Properties.Resources.Convoy);
            //_trajLayout = this.CreateTrajectoryLayout(_effect);
        }
        #endregion

        #region Public Properties
        public Fleet Fleet
        {
            get
            {
                return _Fleet;
            }
            private set
            {
                if (_Fleet != value)
                {
                    RaisePropertyChanging("Fleet");
                    _Fleet = value;
                    RaisePropertyChanged("Fleet");
                }
            }
        }
        private Fleet _Fleet;
        
        public ILocation Origin
        {
            get
            {
                return _Origin;
            }
            private set
            {
                if (_Origin != value)
                {
                    RaisePropertyChanging("Origin");
                    _Origin = value;
                    RaisePropertyChanged("Origin");
                }
            }
        }
        private ILocation _Origin;

        public ILocation Destination
        {
            get
            {
                return _Destination;
            }
            private set
            {
                if (_Destination != value)
                {
                    RaisePropertyChanging("Destination");
                    _Destination = value;
                    RaisePropertyChanged("Destination");
                }
            }
        }
        private ILocation _Destination;
        
        public DateTime StartTime
        {
            get
            {
                return _StartTime;
            }
            private set
            {
                if (_StartTime != value)
                {
                    RaisePropertyChanging("StartTime");
                    _StartTime = value;
                    RaisePropertyChanged("StartTime");
                }
            }
        }
        private DateTime _StartTime;
        
        public DateTime EndTime
        {
            get
            {
                return _EndTime;
            }
            private set
            {
                if (_EndTime != value)
                {
                    RaisePropertyChanging("EndTime");
                    _EndTime = value;
                    RaisePropertyChanged("EndTime");
                }
            }
        }
        private DateTime _EndTime;
        #endregion

        #region ObservableObject Overrides
        protected override void OnPropertyChanging(System.ComponentModel.PropertyChangingEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");

            base.OnPropertyChanging(e);

            if (e.PropertyName == "Fleet")
            {
                if (!object.ReferenceEquals(Fleet, null))
                    Fleet.ParentOrthonormality = null;
            }
        }

        protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");

            base.OnPropertyChanged(e);

            if (e.PropertyName == "Fleet")
            {
                if (!object.ReferenceEquals(Fleet, null))
                    Fleet.ParentOrthonormality = this;
            }
            else if (e.PropertyName == "StartTime")
            {
                //_needRefreshStartGameTime = true;
                _duration = (float)(EndTime - StartTime).TotalMilliseconds;
            }
            else if (e.PropertyName == "EndTime")
            {
                _duration = (float)(EndTime - StartTime).TotalMilliseconds;
            }
        }
        #endregion

        #region ILocation Implementation
        IList<Fleet> ILocation.Fleets
        {
            get { return Fleets; }
        }

        protected IList<Fleet> Fleets
        {
            get { return new List<Fleet> { Fleet }; }
        }
        #endregion

        #region IOrthonormality Implementation
        protected internal override IEnumerable<IPosition> ChildElements
        {
            get
            {
                return Fleets;
            }
        }
        #endregion

        //#region Rendering
        //void IRenderSprite.RenderSprite()
        //{
        //    RenderSprite();
        //}

        //void IRenderTrajectory.RenderTrajectory()
        //{
        //    RenderTrajectory();
        //}

        //protected internal virtual void RenderSprite()
        //{
        //    Fleet.RenderSprite();
        //}

        //protected internal virtual void RenderTrajectory()
        //{
        //    Buffer verticesBuffer = null;
        //    Buffer alphasBuffer = null;

        //    try
        //    {
        //        ComputeTrajectory(EngineParameters.SPACE_ELEMENT_TRAJECTORY_DIVISION);

        //        //Calcul des variables du shader
        //        var viewMatrix = SceneHelper.GetViewMatrix();
        //        var projectionMatrix = SceneHelper.GetProjectionMatrix();

        //        //Affectation des variables du shader
        //        this._effect.GetVariableByName("g_mView").AsMatrix().SetMatrix(viewMatrix);
        //        this._effect.GetVariableByName("g_mProjection").AsMatrix().SetMatrix(projectionMatrix);

        //        //Créer les différents buffers
        //        verticesBuffer = BufferHelper.CreateBuffer<Vector3>(this._trajVertices);
        //        alphasBuffer = BufferHelper.CreateBuffer<float>(this._trajAlphas);

        //        //Créée le buffer de vertex
        //        var binding = new[]
        //        {
        //            new VertexBufferBinding(verticesBuffer, Marshal.SizeOf(typeof(Vector3)), 0),
        //            new VertexBufferBinding(alphasBuffer, Marshal.SizeOf(typeof(float)), 0)
        //        };

        //        //Envoie les données à l'Input Assembler
        //        Engine.Current.Device.InputAssembler.SetInputLayout(this._trajLayout);
        //        Engine.Current.Device.InputAssembler.SetPrimitiveTopology(PrimitiveTopology.LineStrip);
        //        Engine.Current.Device.InputAssembler.SetIndexBuffer(null, Format.Unknown, 0);
        //        Engine.Current.Device.InputAssembler.SetVertexBuffers(0, binding);

        //        //Effectue les différentes passes
        //        var technique = this._effect.GetTechniqueByName("RenderTrajectory");
        //        for (int pass = 0; pass < technique.Description.PassCount; ++pass)
        //        {
        //            technique.GetPassByIndex(pass).Apply();
        //            Engine.Current.Device.Draw(this._trajVertices.Count, 0);
        //        }
        //    }
        //    finally
        //    {
        //        //Réinitialise les buffers
        //        verticesBuffer.Dispose();
        //        verticesBuffer = null;
        //        alphasBuffer.Dispose();
        //        alphasBuffer = null;
        //        Engine.Current.Device.InputAssembler.SetIndexBuffer(null, Format.Unknown, 0);
        //        Engine.Current.Device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding());
        //    }
        //}

        //private void ComputeTrajectory(int div)
        //{
        //    if (object.ReferenceEquals(this._trajVertices, null))
        //        this._trajVertices = new List<Vector3>();
        //    else
        //        this._trajVertices.Clear();

        //    if (object.ReferenceEquals(this._trajAlphas, null))
        //        this._trajAlphas = new List<float>();
        //    else
        //        this._trajAlphas.Clear();

        //    Vector3 origin = Origin.AbsolutePosition.Vector;
        //    Vector3 dest = Destination.AbsolutePosition.Vector;
        //    Vector3 traj = dest - origin;
        //    var div1 = (int)(_progress * div) ;

        //    for (int t = 0; t <= div1; t++)
        //    {
        //        var part = (float)t / (float)div;
        //        Vector3 vector = Vector3.Add(origin, traj * part);
        //        float alpha = part / _progress;

        //        this._trajVertices.Add(vector);
        //        this._trajAlphas.Add(alpha);
        //    }


        //    for (int t = div1 + 1; t <= div; t++)
        //    {
        //        var part = (float)t / (float)div;
        //        Vector3 vector = Vector3.Add(origin, traj * part);
        //        float alpha = 0.1f;

        //        this._trajVertices.Add(vector);
        //        this._trajAlphas.Add(alpha);
        //    }
        //}
        //#endregion

        //#region ITimeDependent Implementation
        //void ITimeDependent.SetTime(long gameTime)
        //{
        //    SetTime(gameTime);
        //}

        //protected virtual void SetTime(long gameTime)
        //{
        //    if (_needRefreshStartGameTime)
        //    {
        //        _startGameTime = gameTime;
        //        _needRefreshStartGameTime = false;
        //    }
        //    if (gameTime > _startGameTime + _duration)
        //    {
        //        Destination.Fleets.Add(Fleet);
        //        ConvoyManager.UnRegisterConvoy(this);
        //    }
        //    else
        //    {
        //        _elapsed = gameTime - _startGameTime;
        //        _progress = _elapsed / _duration;
        //    }
        //}
        //#endregion

        #region IPosition Implementation
        Spherical IPosition.Position
        {
            get
            {
                return Position;
            }
        }

        protected new Spherical Position
        {
            get
            {
                return AbsolutePosition;
            }
        }

        public new Spherical AbsolutePosition
        {
            get
            {
                return Origin.AbsolutePosition; // *(1 - _progress) + _progress * Destination.AbsolutePosition;
            }
        }
        #endregion
    }
}
